package sealed;

import java.util.ArrayList;
import java.util.HashMap;

sealed interface JSONValue permits JSONArray, JSONObject, JSONPrimitive {
    public default String type() {
        return switch (this) {
            case JSONArray _ -> "array";
            case JSONObject _ -> "object";
            case JSONNumber _ -> "number";
            case JSONString _ -> "string";
            case JSONBoolean _ -> "boolean";
            default -> "null";
        };
    }
}

final class JSONArray extends ArrayList<JSONValue> implements JSONValue {
}

final class JSONObject extends HashMap<String, JSONValue> implements JSONValue {
    @Override
    public String toString() {
        var result = new StringBuilder("{");
        for (var entry : entrySet()) {
            if (result.length() > 1) {
                result.append(", ");
            }
            result.append("\"").append(entry.getKey()).append("\": ").append(entry.getValue());
        }
        result.append("}");
        return result.toString();
    }
}

sealed interface JSONPrimitive extends JSONValue permits JSONNumber, JSONString, JSONBoolean, JSONNull {
}

final record JSONNumber(double value) implements JSONPrimitive {
    @Override
    public String toString() {
        return "" + value;
    }
}

final record JSONString(String value) implements JSONPrimitive {
    @Override
    public String toString() {
        return "\"" + value.translateEscapes() + "\"";
    }
}

enum JSONBoolean implements JSONPrimitive {
    FALSE, TRUE;

    @Override
    public String toString() {
        return super.toString().toLowerCase();
    }
}

enum JSONNull implements JSONPrimitive {
    INSTANCE;

    @Override
    public String toString() {
        return "null";
    }
}


public class SealedTest {
    public static void main(String[] args) {
        var obj = new JSONObject();
        obj.put("name", new JSONString("Harry"));
        obj.put("salary", new JSONNumber(90000));
        obj.put("married", JSONBoolean.FALSE);

        var arr = new JSONArray();
        arr.add(new JSONNumber(13));
        arr.add(JSONNull.INSTANCE);

        obj.put("luckyNumbers", arr);

        System.out.println(obj);

        System.out.println(obj.type());
    }
}
